/**
 * Copyright © 2015 - 2017 EntDIY JavaEE Development Framework
 * <p>
 * Site: https://www.entdiy.com, E-Mail: xautlx@hotmail.com
 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.bolt.support.captcha;

import com.bolt.common.io.IoUtil;
import com.bolt.common.utils.JacksonUtil;
import com.bolt.common.utils.RandomUtil;
import com.bolt.common.utils.StrUtil;
import com.bolt.convention.exception.ServiceException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.util.Base64Utils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.*;
import java.util.Arrays;
import java.util.Base64;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

/**
 * JCaptcha验证
 */
public class CaptchaUtil {

    private static final Logger logger = LoggerFactory.getLogger(CaptchaUtil.class);

    private static Map<String, String> originalCacheMap = new ConcurrentHashMap();  //滑块底图

    private static Map<String, String> slidingBlockCacheMap = new ConcurrentHashMap(); //滑块

    private static Map<String, String> picClickCacheMap = new ConcurrentHashMap(); //点选文字

    private static Map<String, String[]> fileNameMap = new ConcurrentHashMap<>();


    public static void cacheImage(String captchaOriginalPath, String picClickPath) {
        //滑动拼图
        if (StrUtil.isBlank(captchaOriginalPath)) {
            originalCacheMap.putAll(getResourcesImagesFile("captcha/images/original"));
            slidingBlockCacheMap.putAll(getResourcesImagesFile("captcha/images/slidingBlock"));
        } else {
            originalCacheMap.putAll(getImagesFile(captchaOriginalPath + File.separator + "original"));
            slidingBlockCacheMap.putAll(getImagesFile(captchaOriginalPath + File.separator + "slidingBlock"));
        }
        //点选文字
        if (StrUtil.isBlank(captchaOriginalPath)) {
            picClickCacheMap.putAll(getResourcesImagesFile("captcha/images/pic-click"));
        } else {
            picClickCacheMap.putAll(getImagesFile(picClickPath));
        }
        fileNameMap.put(CaptchaImageType.ORIGINAL.getCodeValue(), originalCacheMap.keySet().toArray(new String[0]));
        fileNameMap.put(CaptchaImageType.SLIDING_BLOCK.getCodeValue(), slidingBlockCacheMap.keySet().toArray(new String[0]));
        fileNameMap.put(CaptchaImageType.PIC_CLICK.getCodeValue(), picClickCacheMap.keySet().toArray(new String[0]));
        logger.info("初始化底图:{}", JacksonUtil.toJSONString(fileNameMap));
    }

    private static Map<String, String> getResourcesImagesFile(String path)  {
        try{
            //默认提供六张底图
            Map<String, String> imgMap = new HashMap<>();
            Resource[] images = new PathMatchingResourcePatternResolver().getResources("classpath:" + path + "/*.png");
            for (Resource image : images) {
                InputStream resourceAsStream = image.getInputStream();
                byte[] bytes = IoUtil.readBytes(resourceAsStream);
                String string = Base64Utils.encodeToString(bytes);
                String filename = image.getFilename();
                imgMap.put(filename, string);
            }
            return imgMap;
        }catch (Exception ex){
            throw new ServiceException(ex);
        }

    }

    private static Map<String, String> getImagesFile(String path) {
        Map<String, String> imgMap = new HashMap<>();
        File file = new File(path);
        if (!file.exists()) {
            return new HashMap<>();
        }
        File[] files = file.listFiles();
        Arrays.stream(files).forEach(item -> {
            try {
                FileInputStream fileInputStream = new FileInputStream(item);
                byte[] bytes = IoUtil.readBytes(fileInputStream);
                String string = Base64Utils.encodeToString(bytes);
                imgMap.put(item.getName(), string);
            } catch (FileNotFoundException e) {
                logger.error(e.getMessage(), e);
            } catch (IOException e) {
                logger.error(e.getMessage(), e);
            }
        });
        return imgMap;
    }


    public static BufferedImage getOriginal() {
        String[] strings = fileNameMap.get(CaptchaImageType.ORIGINAL.getCodeValue());
        if (null == strings || strings.length == 0) {
            return null;
        }
        Integer randomInt = RandomUtil.randomInt(0, strings.length);
        String s = originalCacheMap.get(strings[randomInt]);
        return getBase64StrToImage(s);
    }

    public static String getslidingBlock() {
        String[] strings = fileNameMap.get(CaptchaImageType.SLIDING_BLOCK.getCodeValue());
        if (null == strings || strings.length == 0) {
            return null;
        }
        Integer randomInt = RandomUtil.randomInt(0, strings.length);
        String s = slidingBlockCacheMap.get(strings[randomInt]);
        return s;
    }

    public static BufferedImage getPicClick() {
        String[] strings = fileNameMap.get(CaptchaImageType.PIC_CLICK.getCodeValue());
        if (null == strings || strings.length == 0) {
            return null;
        }
        Integer randomInt = RandomUtil.randomInt(0, strings.length);
        String s = picClickCacheMap.get(strings[randomInt]);
        return getBase64StrToImage(s);
    }

    /**
     * 图片转base64 字符串
     *
     * @param templateImage
     * @return
     */
    public static String getImageToBase64Str(BufferedImage templateImage) {
        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        try {
            ImageIO.write(templateImage, "png", baos);
        } catch (IOException e) {
            e.printStackTrace();
        }
        byte[] bytes = baos.toByteArray();
        Base64.Encoder encoder = Base64.getEncoder();
        return encoder.encodeToString(bytes).trim();
    }

    /**
     * base64 字符串转图片
     *
     * @param base64String
     * @return
     */
    public static BufferedImage getBase64StrToImage(String base64String) {
        try {
            Base64.Decoder decoder = Base64.getDecoder();
            byte[] bytes = decoder.decode(base64String);
            ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes);
            return ImageIO.read(inputStream);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }


}